package com.rpc;

import com.rpc.connection.ZkConnection;
import com.rpc.registry.RpcRegistry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs;

import java.io.IOException;
import java.io.InputStream;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.registry.LocateRegistry;
import java.util.List;
import java.util.Properties;

//框架入口
public class RpcFactory {

    //用于保存配置信息
    private static final Properties config = new Properties();
    //自动注册服务配置信息
    private static final Properties services = new Properties();
    //链接对象
    private static ZkConnection connection;
    //注册器对象
    private static RpcRegistry registry;

    /**
     * 初始化过程
     * 固定逻辑 在 classpath 下，提供配置文件 命名为: rpc.properties
     * 配置文件结构为:
     *   registry.ip=服务端IP地址 默认为localhost
     *   registry.port=服务端端口号 默认为：9090
     *   zk.server=zookeeper访问地址，默认是localhost:2181
     *   zk.sessionTimeout=zookeeper 链接会话超时时间，默认为 10000
     */
    static {
        //获取classpath 类路径下配置文件输入流
        InputStream input = RpcFactory.class.getClassLoader().getResourceAsStream("rpc.properties");
        //读取配置文件初始化配置对象
        try {
            config.load(input);
            String serverIp = config.getProperty("registry.ip") == null?"localhost": config.getProperty("registry.ip");
            int serverPort =  config.getProperty("registry.port") == null?9090: Integer.parseInt(config.getProperty("registry.port"));
            String zkServer = config.getProperty("zk.server") == null?"localhost:2181": config.getProperty("zk.server");
            int zkSessionTimeout = config.getProperty("zk.sessionTimeout") == null?10000: Integer.parseInt(config.getProperty("zk.sessionTimeout"));

            //创建链接对象
            connection = new ZkConnection(zkServer, zkSessionTimeout);
            //创建注册器对象
            registry = new RpcRegistry();
            registry.setIp(serverIp);;
            registry.setPort(serverPort);
            registry.setConnection(connection);

            //创建一个 rim 的注册器
            LocateRegistry.createRegistry(serverPort);


            //初始化zk 中的父节点
            List<String> children = connection.getConection().getChildren("/", false);
            if (!children.contains("rpctest")){//不存在节点则创建
                connection.getConection().create("/rpctest", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }
            List<String> rpctestchildren = connection.getConection().getChildren("/rpctest", false);
            if (!rpctestchildren.contains("rpc")){//不存在节点则创建
                connection.getConection().create("/rpctest/rpc", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }

            //再classpath 下是否有一个 rpc-services.properties
            //自动加载配置类
            InputStream serviceInput = RpcFactory.class.getClassLoader().getResourceAsStream("rpc-services.properties");
            if (serviceInput != null){
                services.load(serviceInput);
                for (Object key : services.keySet()){
                    //通过key 查询value
                    Object value = services.get(key);
                    //key 是接口的全命名 value 是实现类的全命名
                    Class<Remote> serviceInterface = (Class<Remote>) Class.forName(key.toString());
                    Remote serviceObject = (Remote) Class.forName(value.toString()).newInstance();
                    //有了接口和服务对象开始注册
                    registry.registerService(serviceInterface, serviceObject);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            //当初始化代码发生异常时，抛出异常，终端虚拟器
            throw new ExceptionInInitializerError(e);
        }
    }

    //提供一个快速注册服务和创建客户端代理对象的静态工具方法
    public static void registerService(Class<? extends Remote> serviceInterface, Remote serviceObject) throws IOException, InterruptedException, KeeperException {
        registry.registerService(serviceInterface, serviceObject);
    }

    public static <T extends Remote> T getServiceProxy(Class<T> serviceInterface) throws NotBoundException, IOException, InterruptedException, KeeperException {
        return registry.getServiceProxy(serviceInterface);
    }
}
